package cn.miju.admin.biz.service.impl;
import java.security.KeyPair;
import java.time.LocalDateTime;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.miju.admin.biz.service.MerchantService;
import cn.miju.admin.biz.vo.*;
import cn.miju.admin.framework.exception.ServiceException;
import cn.miju.common.util.ValidationUtil;
import cn.miju.database.constant.DbConstant;
import cn.miju.database.entity.Merchant;
import cn.miju.database.model.AlipayMerchantProperties;
import cn.miju.database.model.UnionPayMerchantProperties;
import cn.miju.database.model.WechatpayMerchantProperties;
import cn.miju.database.service.MerchantDataService;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <pre>
 * 商户管理
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-04-27 15:43
 */
@Service
@RequiredArgsConstructor
public class MerchantServiceImpl implements MerchantService {
    private final MerchantDataService merchantDataService;

    /**
     * 商户分页查询
     * @param inVO {@link MerchantPageInVO}
     * @return {@link Page<MerchantPageOutVO>}
     */
    @Override
    public Page<MerchantPageOutVO> getPage(MerchantPageInVO inVO) {
        LambdaQueryWrapper<Merchant> queryWrapper = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(inVO.getKeyword())) {
            queryWrapper.like(Merchant::getMerchantName, inVO.getKeyword());
        }
        Page<Merchant> merchantPage = merchantDataService.page(new Page<>(inVO.getPage(), inVO.getPageSize()), queryWrapper);
        Page<MerchantPageOutVO> page = new Page<>();
        BeanUtil.copyProperties(merchantPage, page);
        if (CollUtil.isNotEmpty(merchantPage.getRecords())) {
            page.setRecords(merchantPage.getRecords().stream().
                    map(merchant -> BeanUtil.copyProperties(merchant, MerchantPageOutVO.class)).collect(Collectors.toList()));
        }
        return page;
    }

    /**
     * 查询商户详情
     * @param inVO {@link MerchantDetailInVO}
     * @return {@link MerchantDetailOutVO}
     */
    @Override
    public MerchantDetailOutVO getDetail(MerchantDetailInVO inVO) {
        Merchant merchant = merchantDataService.getById(inVO.getId());
        if (Objects.isNull(merchant)) {
            throw new ServiceException("商户信息不存在！");
        }
        MerchantDetailOutVO outVO = BeanUtil.copyProperties(merchant, MerchantDetailOutVO.class);
        switch (merchant.getMerchantType()) {
            case DbConstant.MerchantType.ALIPAY:
                outVO.setAlipayProperties(BeanUtil.copyProperties(merchant.getAlipayMerchantProperties(), MerchantDetailOutVO.MDAlipayProperties.class));
                break;
            case DbConstant.MerchantType.WECHAT:
                //todo 待补充
                break;
            case DbConstant.MerchantType.UNIONPAY:
                outVO.setUnionPayProperties(BeanUtil.copyProperties(merchant.getUnionPayMerchantProperties(), MerchantDetailOutVO.MDUnionPayProperties.class));
                break;
            default:
                break;
        }
        return outVO;
    }

    /**
     * 保存|修改商户信息
     * @param inVO {@link MerchantSaveInVO}
     */
    @Override
    public void saveOrUpdate(MerchantSaveInVO inVO) {
        Merchant merchant;
        if (Objects.isNull(inVO.getId())) {
            merchant = BeanUtil.copyProperties(inVO, Merchant.class);
            merchant.setPlatformMerchantNo(RandomUtil.randomString(18));
            KeyPair keyPair = SecureUtil.generateKeyPair("RSA");
            merchant.setPublicKey(Base64.encode(keyPair.getPublic().getEncoded()));
            merchant.setPrivateKey(Base64.encode(keyPair.getPrivate().getEncoded()));
            merchant.setToMerchantTradeNo(inVO.isToMerchantTradeNo());
            merchant.setStatus(DbConstant.MerchantStatus.DISABLE);
        } else {
            merchant = merchantDataService.getById(inVO.getId());
            if (Objects.isNull(merchant)) {
                throw new ServiceException("商户信息不存在！");
            }
            merchant.setMerchantName(inVO.getMerchantName());
            merchant.setMerchantType(inVO.getMerchantType());
            merchant.setPayNotifyUrl(inVO.getPayNotifyUrl());
            merchant.setRefundNotifyUrl(inVO.getRefundNotifyUrl());
            merchant.setToMerchantTradeNo(inVO.isToMerchantTradeNo());
            merchant.setUpdatedTime(LocalDateTime.now());
        }
        switch (merchant.getMerchantType()) {
            case DbConstant.MerchantType.ALIPAY:
                if (Objects.isNull(inVO.getAlipayProperties())) {
                    throw new ServiceException("传入支付宝商户配置参数不能为空！");
                }
                ValidationUtil.validate(inVO.getAlipayProperties());
                merchant.setMerchantProperties(JSONObject.toJSONString(BeanUtil.copyProperties(inVO.getAlipayProperties(), AlipayMerchantProperties.class)));
                break;
            case DbConstant.MerchantType.WECHAT:
                if (Objects.isNull(inVO.getWechatpayProperties())) {
                    throw new ServiceException("传入微信商户配置参数不能为空！");
                }
                ValidationUtil.validate(inVO.getWechatpayProperties());
                merchant.setMerchantProperties(JSONObject.toJSONString(BeanUtil.copyProperties(inVO.getWechatpayProperties(), WechatpayMerchantProperties.class)));
                break;
            case DbConstant.MerchantType.UNIONPAY:
                if (Objects.isNull(inVO.getUnionPayProperties())) {
                    throw new ServiceException("传入银联商户配置参数不能为空！");
                }
                ValidationUtil.validate(inVO.getUnionPayProperties());
                merchant.setMerchantProperties(JSONObject.toJSONString(BeanUtil.copyProperties(inVO.getUnionPayProperties(), UnionPayMerchantProperties.class)));
                break;
            default:
                break;
        }
        merchantDataService.saveOrUpdate(merchant);
    }

    /**
     * 批量删除商户
     * @param inVO {@link MerchantDeleteInVO}
     */
    @Override
    public void deletes(MerchantDeleteInVO inVO) {
        merchantDataService.removeBatchByIds(inVO.getIds());
    }

    /**
     * 修改商户状态
     * @param inVO {@link MerchantUpdateStatusInVO}
     */
    @Override
    public void updateStatus(MerchantUpdateStatusInVO inVO) {
        merchantDataService.update(Wrappers.<Merchant>lambdaUpdate().
                set(Merchant::getStatus, inVO.getStatus()).
                eq(Merchant::getId, inVO.getId()));
    }
}
